# $Id: backends.py 7557b5d4d82b 2012/12/02 09:07:16 pgurumur $
# Copyright (c) 2009 Prabhu Gurumurthy  <pgurumur@gmail.com>
# 
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#

## @package backends
# Backends module, replaces the default SQL based authentication used with
# django, this package provides, local file based authentication and RADIUS
# server based authentication imports auth and radius class from the core
# modules within the project

__version__ =  "$Revision: 7557b5d4d82b $"
__author__ = "$Author: pgurumur $"

import hashlib

from django.conf import settings
from django.contrib.auth.models import User
from django.core.exceptions import ObjectDoesNotExist

from djanet import utils
from djanet.db import netdb
from djanet.lib import stdlib
from djanet.lib.exception import AuthError
from djanet.tools.lib import radius

class Auth(object):
   supports_object_permissions = False
   supports_anonymous_user = True
   def __init__(self):
      self._log = utils.loghandle(stdlib.my_name(self))
      self._err = AuthError()

   def debug(self, Message):
      if hasattr(settings, 'DEBUG') and settings.DEBUG:
         self._log.info(str(Message))

   def _error(self, Message):
      self._log.info(str(Message))
      raise AuthError, str(Message)

   def authenticate(self, username, password):
      raise NotImplementedError()

   def get_user(self, UserId):
      user = None
      try:
         user = User.objects.get(pk = UserId)
      except User.DoesNotExist:
         pass

      return user

   def permissions(self, User):
      netuser = None
      try:
         netuser = netdb.Person.objects.get(username__exact = User.username)
      except ObjectDoesNotExist:
         pass

      if netuser:
         if netuser.user_type == 1:
            User.is_superuser = True
         elif netuser.user_type == 2:
            User.is_superuser = True
         else:
            User.is_superuser = False
      else:
         User.is_superuser = False

      return User

class Radius(Auth):
   def __init__(self):
      super(self.__class__, self).__init__()
      self._radius = None

      if hasattr(settings, 'RADIUS'):
         server = None
         secret = None
         timeout = 5
         port = 1812
         retries = 3

         if 'SERVER' in settings.RADIUS and 'SECRET' in settings.RADIUS:
            server = settings.RADIUS['SERVER']
            secret = settings.RADIUS['SECRET']

         if 'TIMEOUT' in settings.RADIUS:
            timeout = settings.RADIUS['TIMEOUT']

         if 'RETRIES' in settings.RADIUS:
            retries = settings.RADIUS['RETRIES']

         if 'PORT' in settings.RADIUS:
            port = settings.RADIUS['PORT']

         if (server or secret) is None:
            raise AuthError, 'no server or secret attribute in RADIUS settings'

         try:
            if port and retries and timeout:
               self._radius = radius.Radius(server, secret, port, retries,
                     timeout)
            else:
               self._radius = radius.Radius(server, secret)
         except radius.RadiusError, message:
            self._log(message)
      else:
         self._error("no RADIUS attributes defined in settings!")

   ## authenticate function
   # Authenticates the user using flat file,as long as the user is not 
   # explicity denied
   # 
   # @brief function that django backend authentication class to 
   #        authenticate the user
   # @param self: 'this' pointer
   # @param username: username to login as
   # @param password: password for the username
   # @return returns the user model object
   def authenticate(self, username, password):
      user = None

      auth = None
      try:
         auth = self._radius.Authenticate(username, password)
      except radius.RadiusError, message:
         self._log(message)

      if auth:
         try:
            user = User.objects.get(username__exact = username)
         except User.DoesNotExist:
            user = User(username = username)
            if user:
               user.set_password(password)
               user.is_active = True
               user.is_staff = True
               self.permissions(user)
               user.save()
         else:
            if not user.is_superuser:
               self.permissions(user)
               user.save()

      return user

class Local(Auth):
   def __init__(self):
      super(self.__class__, self).__init__()

   def authenticate(self, username, password):
      user = None
      try:
         user = User.objects.get(username__exact = username)
      except User.DoesNotExist:
         self._error('Invalid user %s' %username)

      if not user.check_password(password):
         self._log('Cannot authenticate user %s' %username)
         user = None

      return user
